import glob
import os
import re
import pandas as pd
from tqdm import tqdm


def dealAnswer(answer):
    if answer is None:
        return answer

    model_all = answer.split("\n")

    occurrences = []

    for i, line in enumerate(model_all):
        if "```" in line:
            occurrences.append(i)

    if len(occurrences) == 0:
        return answer

    if len(occurrences) == 1:
        if answer.endswith("```"):
            return "\n".join(model_all[:occurrences[0]])
        else:
            return "\n".join(model_all[occurrences[0] + 1:])
        
    if len(occurrences) == 2: 
        return "\n".join(model_all[occurrences[0] + 1:occurrences[1]])   
    #return "\n".join(model_all[occurrences[len(occurrences)- 2] + 1:occurrences[len(occurrences)-1]])
    mid = len(occurrences) // 2
    if len(occurrences) % 2 == 0:
        return "\n".join(model_all[occurrences[mid - 1] + 1:occurrences[mid]])
    else:
        return "\n".join(model_all[occurrences[mid] + 1:occurrences[mid + 1]])
    
    
def remove_comments(code, lang):
    java_c_cpp = ['java', 'JAVA', 'Java', 'cpp', 'c++', 'CPP', 'c', 'C']
    if lang in java_c_cpp:
        # 去除单行注释
        code = re.sub(r'//.*', '', code)
        # 去除多行注释
        code = re.sub(r'/\*.*?\*/', '', code, flags=re.DOTALL)
    elif lang == 'python' or lang == 'PYTHON':
        code = re.sub(r'#.*', '', code)
    elif lang.lower() == 'js' or lang.lower() == 'javascript':
        code = re.sub(r'//.*', '', code)
        code = re.sub(r'/\*.*?\*/', '', code, flags=re.DOTALL)
    elif lang == 'go' or lang == 'golang':
        code = re.sub(r'//.*', '', code)
        code = re.sub(r'/\*.*?\*/', '', code, flags=re.DOTALL)
    return code    



def clean_text_advanced(text):
    # 去掉大括号 {}
    text = re.sub(r"[{}]", "", text)

    # 去掉空行
    text = re.sub(r"\n\s*\n", "\n", text)

    # 去掉开头和结尾的空行
    text = text.strip()

    # 去掉行尾的空白字符
    text = re.sub(r"[ \t]+$", "", text, flags=re.MULTILINE)

    return text



def jaccard_similarity(str1, str2):
    set1 = set(str1)
    set2 = set(str2)
    intersection = len(set1.intersection(set2))
    union = len(set1.union(set2))
    if union == 0:
        return 0
    return intersection / union



def get_similar(target, model_answer, lauguage):
    target_all = target.split("\n")
    model_all = model_answer.split("\n")
    if "```" + lauguage in model_all:
        index = model_all.index("```" + lauguage)
        model_line = model_all[index + 1:len(model_all)]
        if "```" in model_line:
            index1 = model_line.index("```")
            model_line = model_line[:index1]
    else:
        model_line = model_all

    #print("\n".join(model_line))
    if target.startswith('```'):
        target_line = target_all[1:len(target_all) - 1]
    else:
        target_line = target_all
    #print("\n".join(target_line))
    if len(target_line) < len(model_line):
        return jaccard_similarity('\n'.join(target_line), '\n'.join(model_line))
    target_answer = target_line[:len(model_line)]
    simmilar1 = jaccard_similarity('\n'.join(target_answer), '\n'.join(model_line))
    simmilar2 = 0.0
    simmilar3 = 0.0
    simmilar4 = 0.0
    simmilar5 = 0.0
    #(str(simmilar1))

    if len(model_line) + 1 <= len(target_line):
        target_answer = target_line[1:len(model_line) + 1]
        simmilar2 = jaccard_similarity('\n'.join(target_answer), '\n'.join(model_line)) - 0.05

    if len(model_line) + 2 <= len(target_line):
        target_answer = target_line[1:len(model_line) + 2]
        simmilar3 = jaccard_similarity('\n'.join(target_answer), '\n'.join(model_line)) - 0.1

    if len(model_line) + 3 <= len(target_line):
        target_answer = target_line[1:len(model_line) + 3]
        simmilar4 = jaccard_similarity('\n'.join(target_answer), '\n'.join(model_line)) - 0.15

    if len(model_line) + 4 <= len(target_line):
        target_answer = target_line[1:len(model_line) + 4]
        simmilar5 = jaccard_similarity('\n'.join(target_answer), '\n'.join(model_line)) - 0.15
    return max(simmilar1, simmilar2, simmilar3, simmilar4, simmilar5)


def dealTarget(target):
    target_all = target.split("\n")
    print(target_all)
    if "``" in target_all:
        first_index, last_index = find_indices_of_target(target_all, "``")
        print(str(first_index))
        print(str(last_index))
        target_line = target_all[first_index + 1: last_index]
    else:
        target_line = target_all        

    target = "\n".join(target_line)
    return target


def find_indices_of_target(target_all, target):
    # 初始化一个空列表来存储找到的索引
    indices = []

    # 遍历target_all中的每个元素
    for element in target_all:
        # 查找目标字符串在当前元素中的索引
        index = element.find(target)
        # 如果找到了目标字符串，将其索引添加到indices列表中
        if index != -1:
            index1 = target_all.index(element)
            indices.append(index1)

    # 如果没有找到任何索引，返回None
    if not indices:
        return None, None

    # 返回第一个和最后一个出现的索引
    return min(indices), max(indices)



def hw_evaluate_hit_ratio(target: str, model_answer: str, lauguage: str) -> float:
    target_all = target.split("\n")
    model_all = model_answer.split("\n")
    actual_lines = model_all
    expect_lines = target_all
    if "```" + lauguage in model_all:
        index = model_all.index("```" + lauguage)
        model_line = model_all[index + 1:len(model_all)]

        if "```" in model_line:
            index1 = model_line.index("```")
            actual_lines = model_line[:index1]
    else:
        actual_lines = model_all

    if target.startswith('```'):
        expect_lines = target_all[1:len(target_all) - 1]
    else:
        expect_lines = target_all

    if not actual_lines or not expect_lines:
        return 0

    def del_spaces(txt: str) -> str:
        return txt.replace(" ", "")

    except_list = []
    actual_list = []
    for exp in expect_lines:
        exp = del_spaces(exp)
        if exp and exp not in "{}":
            except_list.append(exp)

    for act in actual_lines:
        act = del_spaces(act)
        if act and act not in "{}":
            actual_list.append(act)

    len_except = len(except_list)
    len_actual = len(actual_list)

    match_cnt = 0
    for item in except_list:
        if item in actual_list:
            match_cnt += 1
            actual_list.remove(item)
    denominator = len_except
    if not denominator:
        return 0
    return min(100, match_cnt / denominator)

def main(lang):
    # 固定参数
    limit = "0.8,0.9"   # 相似度阈值
    hitlimit = "0.5"  # 命中率阈值

    # 找到同目录下的所有xlsx文件（排除结果文件）
    excel_files = [f for f in glob.glob("*.xlsx") if not f.endswith("_result.xlsx") and not f.endswith("_rate_result.xlsx")]

    if not excel_files:
        print("当前目录下未找到可处理的Excel文件！")
        return

    print(f"发现 {len(excel_files)} 个Excel文件，将依次处理：")
    for f in excel_files:
        print(" -", f)

    for excel_path in excel_files:
        print(f"\n开始处理文件: {excel_path}")

        # 初始化统计字典
        jkddata = {str(x): 0 for x in limit.split(",")}
        hitdata = {str(x): 0 for x in hitlimit.split(",")}

        # 读取Excel
        df = pd.read_excel(excel_path)

        if "标准答案" not in df.columns or "模型答案" not in df.columns:
            print(f"跳过 {excel_path}：缺少 '标准答案' 或 '模型答案' 列")
            continue

        data1 = []
        print(f"读取到 {len(df)} 条数据，开始计算...")
        for _, row in tqdm(df.iterrows(), total=len(df), desc=f"处理 {excel_path}"):
            target = row["标准答案"]
            answer = row["模型答案"]

            # 可选：预处理
            target = dealTarget(target)
            target = remove_comments(target, lang)
            answer = dealAnswer(answer)
            answer = remove_comments(answer, lang)

            # 计算指标
            hit_rate = round(hw_evaluate_hit_ratio(target, answer, lang), 4)
            score = round(get_similar(target, answer, lang), 4)

            print(f"\n标准答案:\n{target}\n模型答案:\n{answer}\n相似度: {score}, 命中率: {hit_rate}")

            # 累计统计
            for limit_scores in limit.split(","):
                if score >= float(limit_scores):
                    jkddata[str(limit_scores)] += 1
            for hit_scores in hitlimit.split(","):
                if hit_rate >= float(hit_scores):
                    hitdata[str(hit_scores)] += 1

            # 保存行结果
            data1.append({
                "标准答案": target,
                "模型答案": answer,
                "相似度": score,
                "命中率": hit_rate
            })

        # 保存详细结果
        base_name = os.path.splitext(excel_path)[0]
        result_file = base_name + "_result.xlsx"
        rate_file = base_name + "_rate_result.xlsx"

        result_df = pd.DataFrame(data1)
        result_df.to_excel(result_file, index=False)

        # 保存统计结果
        resultdata = {}
        for key, value in jkddata.items():
            resultdata[f"jkd_num_{key}"] = value
            resultdata[f"jkd_rate_{key}"] = f"{value / len(df) * 100:.2f}%"
        for key, value in hitdata.items():
            resultdata[f"hit_num_{key}"] = value
            resultdata[f"hit_rate_{key}"] = f"{value / len(df) * 100:.2f}%"

        summary_df = pd.DataFrame([resultdata])
        summary_df.to_excel(rate_file, index=False)

        print(f"文件 {excel_path} 处理完成，结果已保存为：{result_file}, {rate_file}")

    print("\n全部文件处理完成！")


if __name__ == "__main__":
    lang_options = ["java", "js", "python", "ts"]

    while True:
        print("请选择处理语言：")
        for i, lang_name in enumerate(lang_options, 1):
            print(f"{i}. {lang_name}")
        choice = input("请输入对应数字 (1-4)：").strip()
        if choice in ["1", "2", "3", "4"]:
            lang = lang_options[int(choice)-1]
            break
        print("输入不合法，请输入 1 到 4 的数字。")

    main(lang)

       

        
        
    